﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using Np.GalleryDownloader.Classes.Handlers;
using Np.GalleryDownloader.Classes.Extensions;

namespace Np.GalleryDownloader.Classes
{
    public class Downloader : INotifyPropertyChanged
    {
        private string saveDirectory = Environment.GetFolderPath(Environment.SpecialFolder.MyPictures);
        private List<DownloadPage> downloadPages = new List<DownloadPage>();
        private ObservableCollection<DownloadPage> downloadedPages = new ObservableCollection<DownloadPage>();
        //private int threads = 2;
        private string what;
        private string where;
        private WebClient wc = new WebClient();

        private int maxConcurrentDownloads = 5;

        #region Properties

        /// <summary>
        /// Contains last /
        /// </summary>
        public string SaveDirectory
        {
            get { return saveDirectory; }
            set { saveDirectory = value; }
        }

        public List<DownloadPage> DownloadPages
        {
            get { return downloadPages; }
            set { downloadPages = value; }
        }

        public ObservableCollection<DownloadPage> DownloadedPages
        {
            get { return downloadedPages; }
            set { downloadedPages = value; }
        }


        public event UpdateEventHandler Update;
        protected virtual void OnUpdate()
        {
            if (Update != null)
                Update(this);
        }

        public event EventHandler Completed;
        protected virtual void OnCompleted()
        {
            if (Completed != null)
                Completed(this, new EventArgs());
        }
        #endregion

        public Downloader()
        {
            wc.DownloadDataCompleted += wc_DownloadDataCompleted;
            wc.DownloadFileCompleted += wc_DownloadFileCompleted;
            wc.DownloadProgressChanged += wc_DownloadProgressChanged;
        }

        void wc_DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
        {

        }

        void wc_DownloadFileCompleted(object sender, AsyncCompletedEventArgs e)
        {
            OnUpdate();
            TryDownloadFile();
        }


        Queue<DownloadImage> toDownload = new Queue<DownloadImage>();

        public void DownloadAsync()
        {
            foreach (var p in downloadPages)
            {
                foreach (var l in p.ImageLinks)
                {
                    toDownload.Enqueue(l);
                }
            }

            TryDownloadFile();
        }

        private void TryDownloadFile()
        {
            if (toDownload.Any())
            {
                DownloadFile(toDownload.Dequeue());
            }
            else
                OnCompleted();
        }

        private void DownloadFile(DownloadImage l)
        {
            what = l.Link.AbsoluteUri;
            var filename = NotUsedFilename(what);
            where = String.Format(@"{1}\{0}", filename, saveDirectory);
            try
            {
                wc.DownloadFileAsync(new Uri(what), where);
            }
            catch (Exception ee)
            {

            }

            l.DateDownloaded = DateTime.Now;
            l.IsDownloaded = true;
        }

        void wc_DownloadDataCompleted(object sender, DownloadDataCompletedEventArgs e)
        {
            throw new NotImplementedException();
        }


        // TODO: find last number after last underscore
        private string NotUsedFilename(string absoluteUri)
        {
            string filename = absoluteUri.Split('/').Last();
            filename = filename.Replace("?", "");
            filename = filename.Replace("+", "-");
            filename = filename.Replace("%", "-");
            FileInfo file = new FileInfo(String.Format(@"{0}\{1}", saveDirectory, filename));
            var names = GetNames(file);
            if (names.Any())
            {
                int maxNum = 0;

                var namesParts = (from n in names
                                  select new FileInfo(n).FileName().Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries));
                if (namesParts.Any())
                {
                    var maxNums = (from n in namesParts
                              where n.Count() > 1
                              select n.Last().ToInt());
                    if (maxNums.Any())
                        maxNum = maxNums.Max();
                }

                var firstName = (from n in names
                                 orderby n ascending
                                 select new FileInfo(n)).FirstOrDefault();

                var parts = firstName.FileName().Split(new char[] { '_' }, StringSplitOptions.RemoveEmptyEntries);

                string newFilename = string.Empty;
                if (parts.Length == 1)
                    newFilename = parts[0];
                else
                {
                    for (int i = 0; i < parts.Count(); i++)
                    {
                        if (i > 1)
                        {
                            newFilename += "_";
                        }
                        newFilename += parts[i];
                    }
                }
                file = new FileInfo(String.Format(@"{0}\{1}_{2}{3}", saveDirectory, newFilename, maxNum + 1, file.Extension));
                //int max = (number == 1) ? parts.Length : parts.Length - 1;

                // TODO: dopsat generovani novych nazvu souboru

            }
            return file.Name;
        }

        private static string[] GetNames(FileInfo file)
        {
            return Directory.GetFiles(file.DirectoryName, string.Format("{0}*{1}", file.FileName(), file.Extension));
        }

        public event PropertyChangedEventHandler PropertyChanged;

        protected virtual void OnPropertyChanged(string propertyName)
        {
            PropertyChangedEventHandler handler = PropertyChanged;
            if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }
}
